#define KOBOFW_3_1_X


# include "TestPlugin.h"

#include <iostream>

#include <errno.h>
#include <execinfo.h>
#include <signal.h>
#include <cxxabi.h>
#include <sched.h>
/* get REG_EIP from ucontext.h */
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <ucontext.h>

#include <QFile>
#include <QLocale>
#include <QMessageBox>
#include <QTranslator>

#include "PluginInterface.h"
#include "PluginLoader.h"
#include "SocketHandler.h"

#include "Content.h"
#include "GridAndListLibraryView.h"
#include "HomeMenuController.h"
#include "HomePageGridView.h"
#include "MainWindowController.h"
#include "N3FSSyncManager.h"
#include "N3ReaderOpener.h"
#include "N3SettingsController.h"
#include "ReadingFooter.h"
#include "ReadingView.h"
#include "ReadingViewMixin.h"
#include "TouchLabel.h"
#include "Volume.h"
#include "WirelessWatchdog.h"
#include "WirelessWorkflowManager.h"
#include "HomePageHeaderWidget.h"
#include "TweaksSettingsView.h"
#include "TweaksSettingsPageView.h"
#include "FooterLabelWidget.h"
#include "FindBooksMenuController.h"
#include "QuiltedView.h"
#include "DevicePowerWorkflowManager.h"
#include "N3PowerWorkflowManager.h"
#include "ReadingLifeMenuController.h"

#define REQUIRED_VERSION "2.3.0"

using namespace std;


/*********************************************************************************************/
/*********************************************************************************************/

QStringList stackTrace(int nr, int prettyPrint, const void * pSecret)
{
    QStringList trace;

    void* tracePtrs[nr];
    int count = backtrace(tracePtrs, nr);

    if (pSecret)
    {
        ucontext_t *uc = (ucontext_t *)pSecret;

        /* overwrite sigaction with caller's address */
        tracePtrs[1] = (void *) uc->uc_mcontext.fault_address;
    }

    char** funcNames = backtrace_symbols(tracePtrs, count);

    for (int i = 0; i < count; i++)
    {
        QString fncName = funcNames[i];//demangle(funcNames[i], prettyPrint);
        if (fncName.size() > 0)
            trace << fncName;
    }

    // Free the string pointers
    free(funcNames);
    return trace;
}


void sig_handler(int sig, siginfo_t * /*info*/, void *secret)
{
    QFile f("/mnt/onboard/strace.log");
    if(f.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        f.write(qPrintable(QString("catched signal <%1> --> print stacktrace\n").arg(sig)));
        f.write("=========== BEGIN BACKTRACE ==========");

        QStringList fnc = stackTrace(100, 1, secret);
        for (int i = 0; i < fnc.size(); i++ )
            f.write(qPrintable(fnc.at(i)));

        f.write("=========== END BACKTRACE ==========");
        f.close();
    }
}

/*********************************************************************************************/
/*********************************************************************************************/


TestPlugin::TestPlugin() : IShellObject("Plugin",this),
    pluginSettings(new QSettings(CONFIG_PATH, QSettings::IniFormat)),
    sw(NULL),
    m_pglv(NULL),
    lastPatchedMenu(NULL),
    m_pClockTimer(NULL),
    m_pReadingView(NULL),
    m_pExtrasController(NULL)
{
    if(!checkFirmwareVersion())
        return;

    if(pluginSettings->value("Global/scriptSocket", false).toBool())
    {
        engine.globalObject().setProperty("aw", engine.newQObject(QApplication::activeWindow()));
        engine.globalObject().setProperty("app", engine.newQObject(qApp));
        engine.globalObject().setProperty("lcontrol", engine.newQObject(QApplication::activeWindow()->findChild<LibraryMenuController *>()));

        engine.globalObject().setProperty("plugin", engine.newQObject(this));

        tcpServer = new QTcpServer(this);
        if (!tcpServer->listen(QHostAddress::Any, 666))
            cerr << "Unable to start server." << endl;
        connect(tcpServer, SIGNAL(newConnection()), this, SLOT(getConnection()));
    }


    std::cout << "QLocale().name(): " << QLocale().name().toStdString() << std::endl;
    QTranslator* pTranslator = new QTranslator;
    pTranslator->load(QString("koboplus.") + QLocale().name(), ":/koboplus/translations/");
    qApp->installTranslator(pTranslator);

    // register to get notified when the current main window changes
    MainWindowController *mwc = MainWindowController::sharedInstance();
    if (mwc) {
        cout << "found MainWindowController: " << mwc << endl << flush;
        sw = QApplication::activeWindow()->findChild<QStackedWidget *>();
        if (sw) {
            cout << "found QStackedWidget: " << sw << endl << flush;
            connect(sw, SIGNAL(currentChanged(int)), this, SLOT(windowChanged(int)));
            cout << "connected windowChanged signal" << endl << flush;
        }
    }

    m_pExtrasController = new N3SettingsExtrasController;

    connect(&mapper, SIGNAL(mapped(QString)), this, SLOT(open(QString)));


    // install signal handler under Linux
    struct sigaction new_action;

    // set up new handler to specify new action
    new_action.sa_sigaction = sig_handler;
    sigemptyset (&new_action.sa_mask);
    new_action.sa_flags = SA_RESTART | SA_SIGINFO;

    // attach signals to sig_handler
    sigaction(SIGABRT, &new_action, NULL);
    sigaction(SIGFPE, &new_action, NULL);
    sigaction(SIGHUP, &new_action, NULL);
    sigaction(SIGILL, &new_action, NULL);
    sigaction(SIGSEGV, &new_action, NULL);
    sigaction(SIGSYS, &new_action, NULL);
    sigaction(SIGUSR1, &new_action, NULL);

}

TestPlugin::~TestPlugin()
{
    cout << "~TestPlugin()" << endl << flush;
}

QStringList TestPlugin::mimeTypes()
{
    cout << "TestPlugin::mimeTypes()" << endl << flush;

    QStringList mimeTypes;
    mimeTypes << "application/x-kobo-test";
    return mimeTypes;
}

QWidget *TestPlugin::reader(void* /*plugin_state*/, QWidget * /*parent*/)
{
    cout << "TestPlugin::reader()" << endl << flush;
    return NULL;
}

ParserInterface *TestPlugin::parser()
{
    cout << "TestPlugin::parser()" << endl << flush;
    return NULL;
}

void TestPlugin::windowChanged(int index)
{
    cout << "TestPlugin::windowChanged()" << endl << flush;

    QWidget *currentWidget = const_cast<QWidget *>(sw->widget(index));
    if (currentWidget)
    {

        cout << "TestPlugin::windowChanged(), current Widget: " << currentWidget->metaObject()->className();
        cout << " at " << currentWidget << endl << flush;

        dumpChildren(currentWidget);

        // from fw version 2.1.6 onward --> HomePageView
        // previous version 2.1.x --> HomePageGridView
        HomePageView *hpv = qobject_cast<HomePageView *>(currentWidget);
        HomePageGridView *hpgv = qobject_cast<HomePageGridView *>(currentWidget);
        QObject* hpObj = NULL;

        if(hpv)
            hpObj = hpv;
        else
            hpObj = hpgv;

//        GridLibraryView* glv = qobject_cast<GridLibraryView *>(currentWidget);
        ReadingView *readv = qobject_cast<ReadingView *>(currentWidget);
        QuiltedView* quiltv = qobject_cast<QuiltedView *>(currentWidget);

        if(readv)
        {
            m_pReadingView = readv;
            if(pluginSettings->value("Reader/tweakFooter", true).toBool())
                {
                connect(readv, SIGNAL(footerMenuOpened()), this, SLOT(bookFooterOpened()));
                connect(readv, SIGNAL(footerMenuClosed()), this, SLOT(bookFooterClosed()));
                }
        }
        else if (hpObj)
        {
            cout << "TestPlugin::windowChanged() found HomePageGridView, trying to patch menu" << endl << flush;

            QWidget *footer = hpObj->findChild<QWidget *>("wishlistFooter");

            if(pluginSettings->value("Tweaks/hideWishList", false).toBool())
            {
                if (footer)
                    footer->hide();

            }

            // remove HEADER and FindBooks as well as ReadingLife labels
            if(pluginSettings->value("Tweaks/hideKoboShop", false).toBool())
            {
                // hide header in top row
                QWidget *header = hpObj->findChild<QWidget *>("header");
                if(header)
                    header->hide();

                // hide seperator between library and find books
                QWidget *sep = hpObj->findChild<QWidget *>("lineLabel1");
                if (sep)
                    sep->hide();

                // hide findBooks entry
#ifdef KOBOFW_3_1_X
                FooterLabelWidget *findBooks = hpObj->findChild<FooterLabelWidget *>("sync");
#else
                FooterLabelWidget *findBooks = hpObj->findChild<FooterLabelWidget *>("findBooks");
#endif
                if (findBooks)
                    findBooks->hide();

                // hide seperator between find books and reading life
                sep = hpObj->findChild<QWidget *>("lineLabel2");
                if (sep)
                    sep->hide();

                FooterLabelWidget *readingLife = hpObj->findChild<FooterLabelWidget *>("readingLife");
                if (readingLife)
                    readingLife->hide();
            }


            // enable direct library access
            // replace LIBRARY label function with direct access
#ifndef KOBOFW_3_1_X
            if(pluginSettings->value("Tweaks/directLibraryAccess", true).toBool())
            {
                // replace Library with direct call of Libraryview
                FooterLabelWidget *library = hpObj->findChild<FooterLabelWidget *>("library");
                if (library)
                {
                    library->setText(tr("Library"));

                    cout << "library connected" << endl << flush;
                    // patch menu when it's displayed for the first time

#ifdef KOBOFW_3_1_X
                    disconnect(library,SIGNAL(mouseDown()),0,0);
#endif
                    connect(library, SIGNAL(mouseDown()), this, SLOT(library()), (Qt::ConnectionType) 0);
                    library->show();
                }
            }
#endif

            // enable direct shelves access
            // replace FindBooks label function with direct access
            if(pluginSettings->value("Tweaks/directShelvesAccess", true).toBool())
            {
                // show seperator between library and find booksTools
#ifdef KOBOFW_3_1_X
                QWidget *sep = hpObj->findChild<QWidget *>("lineLabel2");
#else
                QWidget *sep = hpObj->findChild<QWidget *>("lineLabel1");
#endif
                if (sep)
                    sep->show();

                // replace findBooks with Shelves
#ifdef KOBOFW_3_1_X
                FooterLabelWidget *findBooks = hpObj->findChild<FooterLabelWidget *>("sync");
#else
                FooterLabelWidget *findBooks = hpObj->findChild<FooterLabelWidget *>("findBooks");
#endif

                if (findBooks)
                {
                    findBooks->setText(tr("Shelves"));

#ifdef KOBOFW_3_1_X
                    findBooks->setPixmap(QString(":/koboplus/icons/menu/shelve_02.png"));
                    disconnect(findBooks, SIGNAL(mouseDown()),0,0);
#endif

                    cout << "findBooks connected" << endl << flush;
                    // patch menu when it's displayed for the first time

                    connect(findBooks, SIGNAL(mouseDown()), this, SLOT(patchFindBooks()), (Qt::ConnectionType) 0);
                    findBooks->show();
                }
            }

            if(pluginSettings->value("Tweaks/showCustomCmds", false).toBool())
            {
                // show seperator between custom cmds and shelves
#ifdef KOBOFW_3_1_X
                QWidget *sep = hpObj->findChild<QWidget *>("lineLabel1");
#else
                QWidget *sep = hpObj->findChild<QWidget *>("lineLabel2");
#endif
                if (sep)
                    sep->show();

                // replace FindBooks with custom commands
                FooterLabelWidget *readingLife = hpObj->findChild<FooterLabelWidget *>("readingLife");
                if (readingLife)
                {
                    readingLife->setText(tr("Tools"));

#ifdef KOBOFW_3_1_X
                    readingLife->setPixmap(QString(":/koboplus/icons/menu/tweak_01.png"));
#endif

                    cout << "readingLife connected" << endl << flush;
                    // patch menu when it's displayed for the first time
                    connect(readingLife, SIGNAL(mouseDown()), this, SLOT(patchReadingLife()), (Qt::ConnectionType) 0);
                    readingLife->show();
                }
            }

        }
        else if(quiltv)
        {
            quiltv->setBackgroundColor(QColor(Qt::black), QColor(Qt::white));
        }
    }
}

void TestPlugin::patchFindBooks()
{
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "patchFindBooks called" << endl << flush;

    LibraryMenuController *pfv = QApplication::activeWindow()->findChildren<LibraryMenuController *>().last();
    if(pfv)
    {
#ifndef KOBOFW_3_1_X
        pfv->setShelvesView(true);
#endif

        pfv->shelves();
    }
}


void TestPlugin::patchReadingLife()
{
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "patchReadingLife called" << endl << flush;

    FooterLabelWidget *readingLife = qApp->activeWindow()->findChild<FooterLabelWidget *>("readingLife");
    if(readingLife)
    {
        dumpChildren(readingLife,"readingLife");

        ReadingLifeMenuController* fbmc = readingLife->findChildren<ReadingLifeMenuController *>().last();
        NickelTouchMenu *ntm = readingLife->findChildren<NickelTouchMenu *>().last();

        if (fbmc && ntm)
        {
            // Clear menu and add entries based on confifindBooksguration

            static QPoint origPos = ntm->pos();
            static int elemHeight = ntm->sizeHint().height()/2;

            ntm->clear();

            pluginSettings->beginGroup("CustomCommands");
            QStringList keys = pluginSettings->allKeys();
            pluginSettings->endGroup();

            // limit custom commands to max 8
            keys = keys.mid(0,8);
            QList<QString>::iterator it;
            for(it=keys.begin();it!=keys.end();it++)
            {
                MenuTextItem *mti = NULL;

                QString shellFunc = pluginSettings->value(QString("CustomCommands/%1").arg(*it),QString()).toString();
                QString text = getCustomCommandTranslation(shellFunc);
                mti = fbmc->createMenuTextItem(ntm, (text.isEmpty()) ? *it : text, false);
                mti->setSelected(false);
                fbmc->addWidgetActionWithMapper(ntm, mti, &mapper, shellFunc, true, true);
                ntm->addSeparator();
            }

            QPoint x = origPos;
            x.setY(origPos.y() + (2-keys.size())*elemHeight);
            x.setY(x.y()+ (abs(2-keys.size())*10));

            cout << qPrintable(QString("x %1 | y %2").arg(x.x()).arg(x.y())) << endl << flush;

            ntm->move(x);
            ntm->update();
        }

    }

    cout << "patchReadingLife end" << endl << flush;
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "-------------------------------------------------------------------" << endl << flush;
    cout << "-------------------------------------------------------------------" << endl << flush;
}

void TestPlugin::library()
{
    cout << "library clicked" << endl << flush;


//    TweaksSettingsView *settingsView = new TweaksSettingsView(this, 0);
//    TweaksSettingsPageView *v = new TweaksSettingsPageView(QApplication::activeWindow(), settingsView, false);
//    MainWindowController::sharedInstance()->pushView(v);
//    cout << "push view" << endl << flush;

//    HomePageFooterView* p = QApplication::activeWindow()->findChildren<HomePageFooterView *>().last();
//    if(p)
//    {
//        cout << qPrintable(p->metaObject()->className()) << endl << flush;
//        p->libraryMouseDown();
//    }
   LibraryMenuController *pfv = QApplication::activeWindow()->findChildren<LibraryMenuController *>().last();
    if(pfv)
    {
        cout << "trigger library" << endl << flush;
#ifndef KOBOFW_3_1_X
        pfv->mine();
#else
        pfv->showLibrary();
#endif
    }
}

void TestPlugin::bookFooterOpened()
{
    if(!m_pReadingView)
        m_pReadingView = qApp->activeWindow()->findChild<ReadingView *>();

    if(m_pReadingView)
    {
        if(pluginSettings->value("Reader/showProgress", true).toBool())
            m_pReadingView->showProgressBar();
    }


    ReadingMenuView* pRMView = qApp->activeWindow()->findChild<ReadingMenuView *>("ReadingMenuView");
    if(pRMView)
    {
        if(pluginSettings->value("Reader/showClock", true).toBool())
        {
            cout << "reading menu view found" << endl << flush;

            QLabel *pClockLabel = pRMView->findChild<QLabel *>("myClockLabel");
            if(!pClockLabel)
            {
                QHBoxLayout* pMainLayout = pRMView->findChild<QHBoxLayout *>("horizontalLayout");
                if(pMainLayout)
                {
                    cout << "layout found" << endl << flush;

                      TouchLabel* dictLabel = pRMView->findChild<TouchLabel *>("dict");

                      QLabel* pClockLabel = new QLabel;
                      m_pClockTimer = new QTimer();
                      QObject::connect(m_pClockTimer, SIGNAL(timeout()), this, SLOT(updateClock()));

                      pClockLabel->setMinimumHeight(25);
                      pClockLabel->setFont(QFont("Arial", 18));
                      pClockLabel->setObjectName("myClockLabel");

                      if(pluginSettings->value("Global/24hourClock", true).toBool())
                          pClockLabel->setText(QTime::currentTime().toString("hh:mm"));
                      else
                          pClockLabel->setText(QTime::currentTime().toString("hh:mm ap"));


                      if(dictLabel)
                      {
                          int idx = pMainLayout->indexOf(dictLabel);
                          pMainLayout->insertSpacing(idx,30);
                          pMainLayout->insertWidget(idx,pClockLabel);

                      }
                      else
                      {
                        pMainLayout->addWidget(pClockLabel);
                      }

                      pClockLabel->show();

                      m_pClockTimer->start(30000);
                      cout << "label added" << endl << flush;
                }
            }
            else
            {
                QLabel *pClockLabel = pRMView->findChild<QLabel *>("myClockLabel");
                if(pClockLabel)
                    pClockLabel->show();
            }
        }
        else
        {
            QLabel *pClockLabel = pRMView->findChild<QLabel *>("myClockLabel");
            if(pClockLabel)
                pClockLabel->hide();
        }

        // show browser btn if configured
        if(pluginSettings->value("Reader/showBrowser", false).toBool())
        {
            if(!pRMView->findChild<TouchLabel *>("browserBtn"))
            {
                QHBoxLayout* pMainLayout = pRMView->findChild<QHBoxLayout *>("horizontalLayout");
                if(pMainLayout)
                {
                    TouchLabel* dictLabel = pRMView->findChild<TouchLabel *>("dict");
                    TouchLabel *browser = new TouchLabel(tr("BROWSER"));
                    if(browser && dictLabel)
                    {
                        browser->setObjectName("browserBtn");
                        browser->setPixmap(QPixmap(":/koboplus/icons/menu/browser_02.png"));
                        //browser->setSelectedPixmap(QPixmap(":/koboplus/icons/menu/browser_02.png"));
                        //browser->setDeselectedPixmap(QPixmap(":/koboplus/icons/menu/browser_02.png"));
                        connect(browser, SIGNAL(tapped()), this, SLOT(openWikipedia ()));

                        int idx = pMainLayout->indexOf(dictLabel);
                        pMainLayout->insertWidget(idx,browser);
                        browser->show();
                    }
                }
            } else
            {
                TouchLabel *browser = pRMView->findChild<TouchLabel *>("browserBtn");
                if(browser)
                    browser->show();
            }
        // if not configured -->hide if found
        }
        else
        {
            TouchLabel *browser = pRMView->findChild<TouchLabel *>("browserBtn");
            if(browser)
                browser->hide();
        }
    }
}

void TestPlugin::bookFooterClosed()
{
    cout << "bookFooterClosed called" << endl << flush;

    if(m_pReadingView)
    {
        if(pluginSettings->value("Reader/showProgress", true).toBool())
            m_pReadingView->hideProgressBar();
    }

    if(m_pClockTimer)
        m_pClockTimer->stop();
}


void TestPlugin::updateClock()
{
    ReadingMenuView* pRMView = qApp->activeWindow()->findChild<ReadingMenuView *>("ReadingMenuView");
    if(pRMView)
    {
       QLabel *pClockLabel = pRMView->findChild<QLabel *>("myClockLabel");
       if(pClockLabel)
       {
           if(pluginSettings->value("Global/24hourClock", true).toBool())
               pClockLabel->setText(QTime::currentTime().toString("hh:mm"));
           else
               pClockLabel->setText(QTime::currentTime().toString("hh:mm ap"));
       }
    }
}


void TestPlugin::open(QString shellFunc)
{
    cout << "open called with mime type " << qPrintable(shellFunc) << endl << flush;

    QStringList calls = shellFunc.split(">>",QString::SkipEmptyParts);

    for(int i=0;i<calls.size();i++)
        RShell::get()->invokeFunction(calls[i]);
}


bool TestPlugin::checkFirmwareVersion()
{
    QString requiredVersion = pluginSettings->value("Global/compatFirmware", REQUIRED_VERSION).toString();

    // check if firmware version matches
    QFile f("/mnt/onboard/.kobo/version");
    if(!f.open(QIODevice::ReadOnly))
        return false;

    char szVersion[100];
    f.readLine(szVersion, 99);
    QString versionString(szVersion);

    cout << qPrintable(QString("Current FirmwareVersion String: %1").arg(szVersion)) << endl << flush;
    QStringList versionParts = versionString.split(",");
    if(versionParts.size() != 6)
        return false;

    cout << qPrintable(QString("Current FirmwareVersion: %1 --> requested %2").arg(versionParts[2]).arg(requiredVersion)) << endl << flush;

    currentFirmwareVersion = versionParts[2];

    if (requiredVersion == "0.0.0")
        return true;

    // now check fw version
    if(versionParts[2] != requiredVersion)
        return false;

    return true;
}

void TestPlugin::rvProcessTap(QString cmd)
{
    cout << "rvProcessTap called" << endl << flush;

    if(m_pReadingView)
    {
        if(cmd == "tap")
            m_pReadingView->processTap(QPoint(50,50));
        else if(cmd == "chapter")
            m_pReadingView->nextChapter(false);
        else if(cmd == "next")
            m_pReadingView->nextPage();
        else if(cmd == "prev")
            m_pReadingView->prevPage();
        else if(cmd == "volume")
        {
            N3PowerWorkflowManager* pPWFM = N3PowerWorkflowManager::sharedInstance();
            if(pPWFM)
            {
                Volume v = pPWFM->getLatestVolume();
                QString tmp;
                tmp = QString("<%1> | <%2> <%3>").arg(v.getTitle()).arg(v.getMimeType()).arg(v.isSideLoaded());
                cout << qPrintable(tmp) << endl << flush;
            }
        }
        else if(cmd == "sudoku")
        {
            if(m_pExtrasController)
                m_pExtrasController->openSudoku();
        }

    }
}


QString TestPlugin::getCustomCommandTranslation(QString func)
{
    QString t;

    // check if it is a command sequence
    if(func.contains(">>"))
        return t;

    if(func.contains("openBrowser"))
        t = QString(tr("Browser"));
    else if(func.contains("connectWifi"))
        t = QString(tr("WiFi"));
    else if(func.contains("uninstallPlugin"))
        t = QString(tr("Uninstall Plugin"));
    else if(func.contains("sync"))
        t = QString(tr("Sync"));
    else if(func.contains("sleep"))
        t = QString(tr("Sleep"));
    else if(func.contains("powerOff"))
        t = QString(tr("Shutdown"));
    else if(func.contains("shelves"))
        t = QString(tr("Shelves"));
    else if(func.contains("readingLife"))
       t = QString(tr("Reading Life"));
    else if(func.contains("sudoku"))
       t = QString(tr("Sudoku"));
    else if(func.contains("chess"))
       t = QString(tr("Chess"));
    else if(func.contains("scribble"))
       t = QString(tr("Scribble"));

    return t;
}

QSharedPointer<QSettings> TestPlugin::settings() {
    return pluginSettings;
}


/*********************************************************************************************/
// Tool support functions
/*********************************************************************************************/


void TestPlugin::uninstallPlugin()
{
    cout << "TestPlugin::uninstallPlugin()" << endl << flush;
    QFile::remove("/usr/local/Kobo/libtest.so");
    QFile::remove("/mnt/onboard/.kobo/koboplugins.ini");
    system("/bin/busybox reboot");
}


void TestPlugin::openWikipedia()
{
    WirelessWorkflowManager::sharedInstance()->openBrowser(QUrl("http://www.wikipedia.org"));
}

void TestPlugin::openBrowser()
{
    WirelessWorkflowManager::sharedInstance()->openBrowser(QUrl());
}

void TestPlugin::connectWifi()
{
    WirelessWorkflowManager* p = WirelessWorkflowManager::sharedInstance();

    if(p)
    {
        if(p->isConnectedToHotspot())
            p->turnWifiOff();
        else
            p->connectWireless(false);
    }
}

void TestPlugin::toogleAirplaneMode()
{
    WirelessWorkflowManager::sharedInstance()->setAirplaneMode(!WirelessWorkflowManager::sharedInstance()->isAirplaneMode());
}

void TestPlugin::executeSystemCmd(QString cmd)
{
    QProcess::execute(cmd);
}

void TestPlugin::sync(bool)
{
    cout << "TestPlugin::sync()" << endl << flush;
    QStringList paths;
    paths << "/mnt/onboard/";
    N3FSSyncManager::sharedInstance()->sync(paths);
}

void TestPlugin::sleep()
{
    N3PowerWorkflowManager::sharedInstance()->toggleSleep();
}

void TestPlugin::powerOff()
{
   N3PowerWorkflowManager::sharedInstance()->powerOff(false);
}


void TestPlugin::shelves()
{
    LibraryMenuController *pfv = QApplication::activeWindow()->findChildren<LibraryMenuController *>().last();
    if(pfv)
    {
        pfv->setShelvesView(true);
        pfv->shelves();
    }

}

void TestPlugin::readingLife()
{
    ReadingLifeMenuController *pfv = QApplication::activeWindow()->findChildren<ReadingLifeMenuController *>().last();
    if(pfv)
    {
        pfv->setStatsView(true);
        pfv->stats();
    }

}

void TestPlugin::sudoku()
{
    if(m_pExtrasController)
        m_pExtrasController->openSudoku();
}

void TestPlugin::chess()
{
    if(m_pExtrasController)
        m_pExtrasController->openChess();
}

void TestPlugin::scribble()
{
    if(m_pExtrasController)
        m_pExtrasController->openScribble();
}

/*********************************************************************************************/
// QT Script support functions
/*********************************************************************************************/

void TestPlugin::getConnection()
{
    clientConnection = tcpServer->nextPendingConnection();
    new SocketHandler(clientConnection, &engine, this);
}

void TestPlugin::registerObject(QObject *object, QString name)
{
    engine.globalObject().setProperty(name, engine.newQObject(object));
}

void TestPlugin::dumpChildren(QObject* pObj, QString propertyName /* = QString() */)
{
    if(pluginSettings->value("Global/dumpLayout", false).toBool() && pObj)
    {
        if(propertyName.isEmpty())
            propertyName = pObj->metaObject()->className();

        if(!engine.globalObject().property(propertyName).isValid())
        {
            engine.globalObject().setProperty(propertyName, engine.newQObject(pObj));

            cout << "Print layout of " << qPrintable(propertyName) << endl << flush;
            // send layout children to log
            QString request = QString("%1.findChildren()").arg(propertyName);
            QString result = engine.evaluate(request).toString();
            cout << qPrintable(result) << endl << flush;
            cout << "End of print layout for " << qPrintable(propertyName) << endl << flush;
        }
    }
}

QObject *findChildByClassname(QObject *o, QString name) {
    if (name == o->metaObject()->className()) {
        return o;
    }

    QListIterator<QObject*> it(o->children());
    while (it.hasNext()) {
        QObject *n = it.next();
        if (n) {
            QObject *r = findChildByClassname(n, name);
            if (r)
                return r;
        }
    }
    return 0;
}

/*********************************************************************************************/
/*********************************************************************************************/

Q_EXPORT_PLUGIN2(tictactoe, TestPlugin)


